1   /*
2    * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  package com.sun.media.sound;
26  
27  import java.io.IOException;
28  import java.util.Arrays;
29  import java.util.HashMap;
30  import java.util.Map;
31  
32  import javax.sound.midi.VoiceStatus;
33  
34  /**
35   * Software synthesizer voice class.
36   *
37   * @author Karl Helgason
38   */
39  public class SoftVoice extends VoiceStatus {
40  
41      public int exclusiveClass = 0;
42      public boolean releaseTriggered = false;
43      private int noteOn_noteNumber = 0;
44      private int noteOn_velocity = 0;
45      private int noteOff_velocity = 0;
46      private int delay = 0;
47      protected ModelChannelMixer channelmixer = null;
48      protected double tunedKey = 0;
49      protected SoftTuning tuning = null;
50      protected SoftChannel stealer_channel = null;
51      protected ModelConnectionBlock[] stealer_extendedConnectionBlocks = null;
52      protected SoftPerformer stealer_performer = null;
53      protected ModelChannelMixer stealer_channelmixer = null;
54      protected int stealer_voiceID = -1;
55      protected int stealer_noteNumber = 0;
56      protected int stealer_velocity = 0;
57      protected boolean stealer_releaseTriggered = false;
58      protected int voiceID = -1;
59      protected boolean sustain = false;
60      protected boolean sostenuto = false;
61      protected boolean portamento = false;
62      private SoftFilter filter_left;
63      private SoftFilter filter_right;
64      private SoftProcess eg = new SoftEnvelopeGenerator();
65      private SoftProcess lfo = new SoftLowFrequencyOscillator();
66      protected Map<String, SoftControl> objects =
67              new HashMap<String, SoftControl>();
68      protected SoftSynthesizer synthesizer;
69      protected SoftInstrument instrument;
70      protected SoftPerformer performer;
71      protected SoftChannel softchannel = null;
72      protected boolean on = false;
73      private boolean audiostarted = false;
74      private boolean started = false;
75      private boolean stopping = false;
76      private float osc_attenuation = 0.0f;
77      private ModelOscillatorStream osc_stream;
78      private int osc_stream_nrofchannels;
79      private float[][] osc_buff = new float[2][];
80      private boolean osc_stream_off_transmitted = false;
81      private boolean out_mixer_end = false;
82      private float out_mixer_left = 0;
83      private float out_mixer_right = 0;
84      private float out_mixer_effect1 = 0;
85      private float out_mixer_effect2 = 0;
86      private float last_out_mixer_left = 0;
87      private float last_out_mixer_right = 0;
88      private float last_out_mixer_effect1 = 0;
89      private float last_out_mixer_effect2 = 0;
90      protected ModelConnectionBlock[] extendedConnectionBlocks = null;
91      private ModelConnectionBlock[] connections;
92      // Last value added to destination
93      private double[] connections_last = new double[50];
94      // Pointer to source value
95      private double[][][] connections_src = new double[50][3][];
96      // Key-based override (if any)
97      private int[][] connections_src_kc = new int[50][3];
98      // Pointer to destination value
99      private double[][] connections_dst = new double[50][];
100     private boolean soundoff = false;
101     private float lastMuteValue = 0;
102     private float lastSoloMuteValue = 0;
103     protected double[] co_noteon_keynumber = new double[1];
104     protected double[] co_noteon_velocity = new double[1];
105     protected double[] co_noteon_on = new double[1];
106     private SoftControl co_noteon = new SoftControl() {
107         double[] keynumber = co_noteon_keynumber;
108         double[] velocity = co_noteon_velocity;
109         double[] on = co_noteon_on;
110         public double[] get(int instance, String name) {
111             if (name == null)
112                 return null;
113             if (name.equals("keynumber"))
114                 return keynumber;
115             if (name.equals("velocity"))
116                 return velocity;
117             if (name.equals("on"))
118                 return on;
119             return null;
120         }
121     };
122     private double[] co_mixer_active = new double[1];
123     private double[] co_mixer_gain = new double[1];
124     private double[] co_mixer_pan = new double[1];
125     private double[] co_mixer_balance = new double[1];
126     private double[] co_mixer_reverb = new double[1];
127     private double[] co_mixer_chorus = new double[1];
128     private SoftControl co_mixer = new SoftControl() {
129         double[] active = co_mixer_active;
130         double[] gain = co_mixer_gain;
131         double[] pan = co_mixer_pan;
132         double[] balance = co_mixer_balance;
133         double[] reverb = co_mixer_reverb;
134         double[] chorus = co_mixer_chorus;
135         public double[] get(int instance, String name) {
136             if (name == null)
137                 return null;
138             if (name.equals("active"))
139                 return active;
140             if (name.equals("gain"))
141                 return gain;
142             if (name.equals("pan"))
143                 return pan;
144             if (name.equals("balance"))
145                 return balance;
146             if (name.equals("reverb"))
147                 return reverb;
148             if (name.equals("chorus"))
149                 return chorus;
150             return null;
151         }
152     };
153     private double[] co_osc_pitch = new double[1];
154     private SoftControl co_osc = new SoftControl() {
155         double[] pitch = co_osc_pitch;
156         public double[] get(int instance, String name) {
157             if (name == null)
158                 return null;
159             if (name.equals("pitch"))
160                 return pitch;
161             return null;
162         }
163     };
164     private double[] co_filter_freq = new double[1];
165     private double[] co_filter_type = new double[1];
166     private double[] co_filter_q = new double[1];
167     private SoftControl co_filter = new SoftControl() {
168         double[] freq = co_filter_freq;
169         double[] ftype = co_filter_type;
170         double[] q = co_filter_q;
171         public double[] get(int instance, String name) {
172             if (name == null)
173                 return null;
174             if (name.equals("freq"))
175                 return freq;
176             if (name.equals("type"))
177                 return ftype;
178             if (name.equals("q"))
179                 return q;
180             return null;
181         }
182     };
183     protected SoftResamplerStreamer resampler;
184     private int nrofchannels;
185 
186     public SoftVoice(SoftSynthesizer synth) {
187         synthesizer = synth;
188         filter_left = new SoftFilter(synth.getFormat().getSampleRate());
189         filter_right = new SoftFilter(synth.getFormat().getSampleRate());
190         nrofchannels = synth.getFormat().getChannels();
191     }
192 
193     private int getValueKC(ModelIdentifier id) {
194         if (id.getObject().equals("midi_cc")) {
195             int ic = Integer.parseInt(id.getVariable());
196             if (ic != 0 && ic != 32) {
197                 if (ic < 120)
198                     return ic;
199             }
200         } else if (id.getObject().equals("midi_rpn")) {
201             if (id.getVariable().equals("1"))
202                 return 120; // Fine tuning
203             if (id.getVariable().equals("2"))
204                 return 121; // Coarse tuning
205         }
206         return -1;
207     }
208 
209     private double[] getValue(ModelIdentifier id) {
210         SoftControl o = objects.get(id.getObject());
211         if (o == null)
212             return null;
213         return o.get(id.getInstance(), id.getVariable());
214     }
215 
216     private double transformValue(double value, ModelSource src) {
217         if (src.getTransform() != null)
218             return src.getTransform().transform(value);
219         else
220             return value;
221     }
222 
223     private double transformValue(double value, ModelDestination dst) {
224         if (dst.getTransform() != null)
225             return dst.getTransform().transform(value);
226         else
227             return value;
228     }
229 
230     private double processKeyBasedController(double value, int keycontrol) {
231         if (keycontrol == -1)
232             return value;
233         if (softchannel.keybasedcontroller_active != null)
234             if (softchannel.keybasedcontroller_active[note] != null)
235                 if (softchannel.keybasedcontroller_active[note][keycontrol]) {
236                     double key_controlvalue =
237                             softchannel.keybasedcontroller_value[note][keycontrol];
238                     if (keycontrol == 10 || keycontrol == 91 || keycontrol == 93)
239                         return key_controlvalue;
240                     value += key_controlvalue * 2.0 - 1.0;
241                     if (value > 1)
242                         value = 1;
243                     else if (value < 0)
244                         value = 0;
245                 }
246         return value;
247     }
248 
249     private void processConnection(int ix) {
250         ModelConnectionBlock conn = connections[ix];
251         double[][] src = connections_src[ix];
252         double[] dst = connections_dst[ix];
253         if (dst == null || Double.isInfinite(dst[0]))
254             return;
255 
256         double value = conn.getScale();
257         if (softchannel.keybasedcontroller_active == null) {
258             ModelSource[] srcs = conn.getSources();
259             for (int i = 0; i < srcs.length; i++) {
260                 value *= transformValue(src[i][0], srcs[i]);
261                 if (value == 0)
262                     break;
263             }
264         } else {
265             ModelSource[] srcs = conn.getSources();
266             int[] src_kc = connections_src_kc[ix];
267             for (int i = 0; i < srcs.length; i++) {
268                 value *= transformValue(processKeyBasedController(src[i][0],
269                         src_kc[i]), srcs[i]);
270                 if (value == 0)
271                     break;
272             }
273         }
274 
275         value = transformValue(value, conn.getDestination());
276         dst[0] = dst[0] - connections_last[ix] + value;
277         connections_last[ix] = value;
278         // co_mixer_gain[0] = 0;
279     }
280 
281     protected void updateTuning(SoftTuning newtuning) {
282         tuning = newtuning;
283         tunedKey = tuning.getTuning(note) / 100.0;
284         if (!portamento) {
285             co_noteon_keynumber[0] = tunedKey * (1.0 / 128.0);
286             if(performer == null)
287                 return;
288             int[] c = performer.midi_connections[4];
289             if (c == null)
290                 return;
291             for (int i = 0; i < c.length; i++)
292                 processConnection(c[i]);
293         }
294     }
295 
296     protected void setNote(int noteNumber) {
297         note = noteNumber;
298         tunedKey = tuning.getTuning(noteNumber) / 100.0;
299     }
300 
301     protected void noteOn(int noteNumber, int velocity, int delay) {
302 
303         sustain = false;
304         sostenuto = false;
305         portamento = false;
306 
307         soundoff = false;
308         on = true;
309         active = true;
310         started = true;
311         // volume = velocity;
312 
313         noteOn_noteNumber = noteNumber;
314         noteOn_velocity = velocity;
315         this.delay = delay;
316 
317         lastMuteValue = 0;
318         lastSoloMuteValue = 0;
319 
320         setNote(noteNumber);
321 
322         if (performer.forcedKeynumber)
323             co_noteon_keynumber[0] = 0;
324         else
325             co_noteon_keynumber[0] = tunedKey * (1f / 128f);
326         if (performer.forcedVelocity)
327             co_noteon_velocity[0] = 0;
328         else
329             co_noteon_velocity[0] = velocity * (1f / 128f);
330         co_mixer_active[0] = 0;
331         co_mixer_gain[0] = 0;
332         co_mixer_pan[0] = 0;
333         co_mixer_balance[0] = 0;
334         co_mixer_reverb[0] = 0;
335         co_mixer_chorus[0] = 0;
336         co_osc_pitch[0] = 0;
337         co_filter_freq[0] = 0;
338         co_filter_q[0] = 0;
339         co_filter_type[0] = 0;
340         co_noteon_on[0] = 1;
341 
342         eg.reset();
343         lfo.reset();
344         filter_left.reset();
345         filter_right.reset();
346 
347         objects.put("master", synthesizer.getMainMixer().co_master);
348         objects.put("eg", eg);
349         objects.put("lfo", lfo);
350         objects.put("noteon", co_noteon);
351         objects.put("osc", co_osc);
352         objects.put("mixer", co_mixer);
353         objects.put("filter", co_filter);
354 
355         connections = performer.connections;
356 
357         if (connections_last == null
358                 || connections_last.length < connections.length) {
359             connections_last = new double[connections.length];
360         }
361         if (connections_src == null
362                 || connections_src.length < connections.length) {
363             connections_src = new double[connections.length][][];
364             connections_src_kc = new int[connections.length][];
365         }
366         if (connections_dst == null
367                 || connections_dst.length < connections.length) {
368             connections_dst = new double[connections.length][];
369         }
370         for (int i = 0; i < connections.length; i++) {
371             ModelConnectionBlock conn = connections[i];
372             connections_last[i] = 0;
373             if (conn.getSources() != null) {
374                 ModelSource[] srcs = conn.getSources();
375                 if (connections_src[i] == null
376                         || connections_src[i].length < srcs.length) {
377                     connections_src[i] = new double[srcs.length][];
378                     connections_src_kc[i] = new int[srcs.length];
379                 }
380                 double[][] src = connections_src[i];
381                 int[] src_kc = connections_src_kc[i];
382                 connections_src[i] = src;
383                 for (int j = 0; j < srcs.length; j++) {
384                     src_kc[j] = getValueKC(srcs[j].getIdentifier());
385                     src[j] = getValue(srcs[j].getIdentifier());
386                 }
387             }
388 
389             if (conn.getDestination() != null)
390                 connections_dst[i] = getValue(conn.getDestination()
391                         .getIdentifier());
392             else
393                 connections_dst[i] = null;
394         }
395 
396         for (int i = 0; i < connections.length; i++)
397             processConnection(i);
398 
399         if (extendedConnectionBlocks != null) {
400             for (ModelConnectionBlock connection: extendedConnectionBlocks) {
401                 double value = 0;
402 
403                 if (softchannel.keybasedcontroller_active == null) {
404                     for (ModelSource src: connection.getSources()) {
405                         double x = getValue(src.getIdentifier())[0];
406                         ModelTransform t = src.getTransform();
407                         if (t == null)
408                             value += x;
409                         else
410                             value += t.transform(x);
411                     }
412                 } else {
413                     for (ModelSource src: connection.getSources()) {
414                         double x = getValue(src.getIdentifier())[0];
415                         x = processKeyBasedController(x,
416                                 getValueKC(src.getIdentifier()));
417                         ModelTransform t = src.getTransform();
418                         if (t == null)
419                             value += x;
420                         else
421                             value += t.transform(x);
422                     }
423                 }
424 
425                 ModelDestination dest = connection.getDestination();
426                 ModelTransform t = dest.getTransform();
427                 if (t != null)
428                     value = t.transform(value);
429                 getValue(dest.getIdentifier())[0] += value;
430             }
431         }
432 
433         eg.init(synthesizer);
434         lfo.init(synthesizer);
435 
436     }
437 
438     protected void setPolyPressure(int pressure) {
439         if(performer == null)
440             return;
441         int[] c = performer.midi_connections[2];
442         if (c == null)
443             return;
444         for (int i = 0; i < c.length; i++)
445             processConnection(c[i]);
446     }
447 
448     protected void setChannelPressure(int pressure) {
449         if(performer == null)
450             return;
451         int[] c = performer.midi_connections[1];
452         if (c == null)
453             return;
454         for (int i = 0; i < c.length; i++)
455             processConnection(c[i]);
456     }
457 
458     protected void controlChange(int controller, int value) {
459         if(performer == null)
460             return;
461         int[] c = performer.midi_ctrl_connections[controller];
462         if (c == null)
463             return;
464         for (int i = 0; i < c.length; i++)
465             processConnection(c[i]);
466     }
467 
468     protected void nrpnChange(int controller, int value) {
469         if(performer == null)
470             return;
471         int[] c = performer.midi_nrpn_connections.get(controller);
472         if (c == null)
473             return;
474         for (int i = 0; i < c.length; i++)
475             processConnection(c[i]);
476     }
477 
478     protected void rpnChange(int controller, int value) {
479         if(performer == null)
480             return;
481         int[] c = performer.midi_rpn_connections.get(controller);
482         if (c == null)
483             return;
484         for (int i = 0; i < c.length; i++)
485             processConnection(c[i]);
486     }
487 
488     protected void setPitchBend(int bend) {
489         if(performer == null)
490             return;
491         int[] c = performer.midi_connections[0];
492         if (c == null)
493             return;
494         for (int i = 0; i < c.length; i++)
495             processConnection(c[i]);
496     }
497 
498     protected void setMute(boolean mute) {
499         co_mixer_gain[0] -= lastMuteValue;
500         lastMuteValue = mute ? -960 : 0;
501         co_mixer_gain[0] += lastMuteValue;
502     }
503 
504     protected void setSoloMute(boolean mute) {
505         co_mixer_gain[0] -= lastSoloMuteValue;
506         lastSoloMuteValue = mute ? -960 : 0;
507         co_mixer_gain[0] += lastSoloMuteValue;
508     }
509 
510     protected void shutdown() {
511         if (co_noteon_on[0] < -0.5)
512             return;
513         on = false;
514 
515         co_noteon_on[0] = -1;
516 
517         if(performer == null)
518             return;
519         int[] c = performer.midi_connections[3];
520         if (c == null)
521             return;
522         for (int i = 0; i < c.length; i++)
523             processConnection(c[i]);
524     }
525 
526     protected void soundOff() {
527         on = false;
528         soundoff = true;
529     }
530 
531     protected void noteOff(int velocity) {
532         if (!on)
533             return;
534         on = false;
535 
536         noteOff_velocity = velocity;
537 
538         if (softchannel.sustain) {
539             sustain = true;
540             return;
541         }
542         if (sostenuto)
543             return;
544 
545         co_noteon_on[0] = 0;
546 
547         if(performer == null)
548             return;
549         int[] c = performer.midi_connections[3];
550         if (c == null)
551             return;
552         for (int i = 0; i < c.length; i++)
553             processConnection(c[i]);
554     }
555 
556     protected void redamp() {
557         if (co_noteon_on[0] > 0.5)
558             return;
559         if (co_noteon_on[0] < -0.5)
560             return; // don't redamp notes in shutdown stage
561 
562         sustain = true;
563         co_noteon_on[0] = 1;
564 
565         if(performer == null)
566             return;
567         int[] c = performer.midi_connections[3];
568         if (c == null)
569             return;
570         for (int i = 0; i < c.length; i++)
571             processConnection(c[i]);
572     }
573 
574     protected void processControlLogic() {
575         if (stopping) {
576             active = false;
577             stopping = false;
578             audiostarted = false;
579             instrument = null;
580             performer = null;
581             connections = null;
582             extendedConnectionBlocks = null;
583             channelmixer = null;
584             if (osc_stream != null)
585                 try {
586                     osc_stream.close();
587                 } catch (IOException e) {
588                     //e.printStackTrace();
589                 }
590 
591             if (stealer_channel != null) {
592                 stealer_channel.initVoice(this, stealer_performer,
593                         stealer_voiceID, stealer_noteNumber, stealer_velocity, 0,
594                         stealer_extendedConnectionBlocks, stealer_channelmixer,
595                         stealer_releaseTriggered);
596                 stealer_releaseTriggered = false;
597                 stealer_channel = null;
598                 stealer_performer = null;
599                 stealer_voiceID = -1;
600                 stealer_noteNumber = 0;
601                 stealer_velocity = 0;
602                 stealer_extendedConnectionBlocks = null;
603                 stealer_channelmixer = null;
604             }
605         }
606         if (started) {
607             audiostarted = true;
608 
609             ModelOscillator osc = performer.oscillators[0];
610 
611             osc_stream_off_transmitted = false;
612             if (osc instanceof ModelWavetable) {
613                 try {
614                     resampler.open((ModelWavetable)osc,
615                             synthesizer.getFormat().getSampleRate());
616                     osc_stream = resampler;
617                 } catch (IOException e) {
618                     //e.printStackTrace();
619                 }
620             } else {
621                 osc_stream = osc.open(synthesizer.getFormat().getSampleRate());
622             }
623             osc_attenuation = osc.getAttenuation();
624             osc_stream_nrofchannels = osc.getChannels();
625             if (osc_buff == null || osc_buff.length < osc_stream_nrofchannels)
626                 osc_buff = new float[osc_stream_nrofchannels][];
627 
628             if (osc_stream != null)
629                 osc_stream.noteOn(softchannel, this, noteOn_noteNumber,
630                         noteOn_velocity);
631 
632 
633         }
634         if (audiostarted) {
635             if (portamento) {
636                 double note_delta = tunedKey - (co_noteon_keynumber[0] * 128);
637                 double note_delta_a = Math.abs(note_delta);
638                 if (note_delta_a < 0.0000000001) {
639                     co_noteon_keynumber[0] = tunedKey * (1.0 / 128.0);
640                     portamento = false;
641                 } else {
642                     if (note_delta_a > softchannel.portamento_time)
643                         note_delta = Math.signum(note_delta)
644                                 * softchannel.portamento_time;
645                     co_noteon_keynumber[0] += note_delta * (1.0 / 128.0);
646                 }
647 
648                 int[] c = performer.midi_connections[4];
649                 if (c == null)
650                     return;
651                 for (int i = 0; i < c.length; i++)
652                     processConnection(c[i]);
653             }
654 
655             eg.processControlLogic();
656             lfo.processControlLogic();
657 
658             for (int i = 0; i < performer.ctrl_connections.length; i++)
659                 processConnection(performer.ctrl_connections[i]);
660 
661             osc_stream.setPitch((float)co_osc_pitch[0]);
662 
663             int filter_type = (int)co_filter_type[0];
664             double filter_freq;
665 
666             if (co_filter_freq[0] == 13500.0)
667                 filter_freq = 19912.126958213175;
668             else
669                 filter_freq = 440.0 * Math.exp(
670                         ((co_filter_freq[0]) - 6900.0) *
671                         (Math.log(2.0) / 1200.0));
672             /*
673             filter_freq = 440.0 * Math.pow(2.0,
674             ((co_filter_freq[0]) - 6900.0) / 1200.0);*/
675             /*
676              * double velocity = co_noteon_velocity[0]; if(velocity < 0.5)
677              * filter_freq *= ((velocity * 2)*0.75 + 0.25);
678              */
679 
680             double q = co_filter_q[0] / 10.0;
681             filter_left.setFilterType(filter_type);
682             filter_left.setFrequency(filter_freq);
683             filter_left.setResonance(q);
684             filter_right.setFilterType(filter_type);
685             filter_right.setFrequency(filter_freq);
686             filter_right.setResonance(q);
687             /*
688             float gain = (float) Math.pow(10,
689             (-osc_attenuation + co_mixer_gain[0]) / 200.0);
690              */
691             float gain = (float)Math.exp(
692                     (-osc_attenuation + co_mixer_gain[0])*(Math.log(10) / 200.0));
693 
694             if (co_mixer_gain[0] <= -960)
695                 gain = 0;
696 
697             if (soundoff) {
698                 stopping = true;
699                 gain = 0;
700                 /*
701                  * if(co_mixer_gain[0] > -960)
702                  *   co_mixer_gain[0] -= 960;
703                  */
704             }
705 
706             volume = (int)(Math.sqrt(gain) * 128);
707 
708             // gain *= 0.2;
709 
710             double pan = co_mixer_pan[0] * (1.0 / 1000.0);
711             // System.out.println("pan = " + pan);
712             if (pan < 0)
713                 pan = 0;
714             else if (pan > 1)
715                 pan = 1;
716 
717             if (pan == 0.5) {
718                 out_mixer_left = gain * 0.7071067811865476f;
719                 out_mixer_right = out_mixer_left;
720             } else {
721                 out_mixer_left = gain * (float)Math.cos(pan * Math.PI * 0.5);
722                 out_mixer_right = gain * (float)Math.sin(pan * Math.PI * 0.5);
723             }
724 
725             double balance = co_mixer_balance[0] * (1.0 / 1000.0);
726             if (balance != 0.5) {
727                 if (balance > 0.5)
728                     out_mixer_left *= (1 - balance) * 2;
729                 else
730                     out_mixer_right *= balance * 2;
731             }
732 
733             if (synthesizer.reverb_on) {
734                 out_mixer_effect1 = (float)(co_mixer_reverb[0] * (1.0 / 1000.0));
735                 out_mixer_effect1 *= gain;
736             } else
737                 out_mixer_effect1 = 0;
738             if (synthesizer.chorus_on) {
739                 out_mixer_effect2 = (float)(co_mixer_chorus[0] * (1.0 / 1000.0));
740                 out_mixer_effect2 *= gain;
741             } else
742                 out_mixer_effect2 = 0;
743             out_mixer_end = co_mixer_active[0] < 0.5;
744 
745             if (!on)
746                 if (!osc_stream_off_transmitted) {
747                     osc_stream_off_transmitted = true;
748                     if (osc_stream != null)
749                         osc_stream.noteOff(noteOff_velocity);
750                 }
751 
752         }
753         if (started) {
754             last_out_mixer_left = out_mixer_left;
755             last_out_mixer_right = out_mixer_right;
756             last_out_mixer_effect1 = out_mixer_effect1;
757             last_out_mixer_effect2 = out_mixer_effect2;
758             started = false;
759         }
760 
761     }
762 
763     protected void mixAudioStream(SoftAudioBuffer in, SoftAudioBuffer out,
764             SoftAudioBuffer dout,
765             float amp_from, float amp_to) {
766         int bufferlen = in.getSize();
767         if (amp_from < 0.000000001 && amp_to < 0.000000001)
768             return;
769         if(dout != null && delay != 0)
770         {
771             if (amp_from == amp_to) {
772                 float[] fout = out.array();
773                 float[] fin = in.array();
774                 int j = 0;
775                 for (int i = delay; i < bufferlen; i++)
776                     fout[i] += fin[j++] * amp_to;
777                 fout = dout.array();
778                 for (int i = 0; i < delay; i++)
779                     fout[i] += fin[j++] * amp_to;
780             } else {
781                 float amp = amp_from;
782                 float amp_delta = (amp_to - amp_from) / bufferlen;
783                 float[] fout = out.array();
784                 float[] fin = in.array();
785                 int j = 0;
786                 for (int i = delay; i < bufferlen; i++) {
787                     amp += amp_delta;
788                     fout[i] += fin[j++] * amp;
789                 }
790                 fout = dout.array();
791                 for (int i = 0; i < delay; i++) {
792                     amp += amp_delta;
793                     fout[i] += fin[j++] * amp;
794                 }
795             }
796         }
797         else
798         {
799             if (amp_from == amp_to) {
800                 float[] fout = out.array();
801                 float[] fin = in.array();
802                 for (int i = 0; i < bufferlen; i++)
803                     fout[i] += fin[i] * amp_to;
804             } else {
805                 float amp = amp_from;
806                 float amp_delta = (amp_to - amp_from) / bufferlen;
807                 float[] fout = out.array();
808                 float[] fin = in.array();
809                 for (int i = 0; i < bufferlen; i++) {
810                     amp += amp_delta;
811                     fout[i] += fin[i] * amp;
812                 }
813             }
814         }
815 
816     }
817 
818     protected void processAudioLogic(SoftAudioBuffer[] buffer) {
819         if (!audiostarted)
820             return;
821 
822         int bufferlen = buffer[0].getSize();
823 
824         try {
825             osc_buff[0] = buffer[SoftMainMixer.CHANNEL_LEFT_DRY].array();
826             if (nrofchannels != 1)
827                 osc_buff[1] = buffer[SoftMainMixer.CHANNEL_RIGHT_DRY].array();
828             int ret = osc_stream.read(osc_buff, 0, bufferlen);
829             if (ret == -1) {
830                 stopping = true;
831                 return;
832             }
833             if (ret != bufferlen) {
834                 Arrays.fill(osc_buff[0], ret, bufferlen, 0f);
835                 if (nrofchannels != 1)
836                     Arrays.fill(osc_buff[1], ret, bufferlen, 0f);
837             }
838 
839         } catch (IOException e) {
840             //e.printStackTrace();
841         }
842 
843         SoftAudioBuffer left = buffer[SoftMainMixer.CHANNEL_LEFT];
844         SoftAudioBuffer right = buffer[SoftMainMixer.CHANNEL_RIGHT];
845         SoftAudioBuffer mono = buffer[SoftMainMixer.CHANNEL_MONO];
846         SoftAudioBuffer eff1 = buffer[SoftMainMixer.CHANNEL_EFFECT1];
847         SoftAudioBuffer eff2 = buffer[SoftMainMixer.CHANNEL_EFFECT2];
848 
849         SoftAudioBuffer dleft = buffer[SoftMainMixer.CHANNEL_DELAY_LEFT];
850         SoftAudioBuffer dright = buffer[SoftMainMixer.CHANNEL_DELAY_RIGHT];
851         SoftAudioBuffer dmono = buffer[SoftMainMixer.CHANNEL_DELAY_MONO];
852         SoftAudioBuffer deff1 = buffer[SoftMainMixer.CHANNEL_DELAY_EFFECT1];
853         SoftAudioBuffer deff2 = buffer[SoftMainMixer.CHANNEL_DELAY_EFFECT2];
854 
855         SoftAudioBuffer leftdry = buffer[SoftMainMixer.CHANNEL_LEFT_DRY];
856         SoftAudioBuffer rightdry = buffer[SoftMainMixer.CHANNEL_RIGHT_DRY];
857 
858         if (osc_stream_nrofchannels == 1)
859             rightdry = null;
860 
861         if (!Double.isInfinite(co_filter_freq[0])) {
862             filter_left.processAudio(leftdry);
863             if (rightdry != null)
864                 filter_right.processAudio(rightdry);
865         }
866 
867         if (nrofchannels == 1) {
868             out_mixer_left = (out_mixer_left + out_mixer_right) / 2;
869             mixAudioStream(leftdry, left, dleft, last_out_mixer_left, out_mixer_left);
870             if (rightdry != null)
871                 mixAudioStream(rightdry, left, dleft, last_out_mixer_left,
872                         out_mixer_left);
873         } else {
874             if(rightdry == null &&
875                     last_out_mixer_left == last_out_mixer_right &&
876                     out_mixer_left == out_mixer_right)
877             {
878                 mixAudioStream(leftdry, mono, dmono, last_out_mixer_left, out_mixer_left);
879             }
880             else
881             {
882                 mixAudioStream(leftdry, left, dleft, last_out_mixer_left, out_mixer_left);
883                 if (rightdry != null)
884                     mixAudioStream(rightdry, right, dright, last_out_mixer_right,
885                         out_mixer_right);
886                 else
887                     mixAudioStream(leftdry, right, dright, last_out_mixer_right,
888                         out_mixer_right);
889             }
890         }
891 
892         if (rightdry == null) {
893             mixAudioStream(leftdry, eff1, deff1, last_out_mixer_effect1,
894                     out_mixer_effect1);
895             mixAudioStream(leftdry, eff2, deff2, last_out_mixer_effect2,
896                     out_mixer_effect2);
897         } else {
898             mixAudioStream(leftdry, eff1, deff1, last_out_mixer_effect1 * 0.5f,
899                     out_mixer_effect1 * 0.5f);
900             mixAudioStream(leftdry, eff2, deff2, last_out_mixer_effect2 * 0.5f,
901                     out_mixer_effect2 * 0.5f);
902             mixAudioStream(rightdry, eff1, deff1, last_out_mixer_effect1 * 0.5f,
903                     out_mixer_effect1 * 0.5f);
904             mixAudioStream(rightdry, eff2, deff2, last_out_mixer_effect2 * 0.5f,
905                     out_mixer_effect2 * 0.5f);
906         }
907 
908         last_out_mixer_left = out_mixer_left;
909         last_out_mixer_right = out_mixer_right;
910         last_out_mixer_effect1 = out_mixer_effect1;
911         last_out_mixer_effect2 = out_mixer_effect2;
912 
913         if (out_mixer_end) {
914             stopping = true;
915         }
916 
917     }
918 }